﻿using ComLib.ComType;
using LogLib;
using Newtonsoft.Json;
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace CoreBroker
{
    public class Readying
    {
        /// <summary>
        /// 用于在主线程中执行操作的同步上下文
        /// </summary>
        private SynchronizationContext _uiContext = null;

        private string _error;
        public string ErrorMessage
        {
            get { return _error; }
            set { _error = value; }
        }

        private string _fileName = "";
   
        /// <summary>
        /// 镜头视频流播放器
        /// </summary>
        private CapturerBroker _capturer = null;
        public CapturerBroker Capturer
        {
            get
            {
                return _capturer;
            }
            set
            {
                _capturer = value;
            }
        }

        /// <summary>
        /// 照片检测结果报告
        /// </summary>
        public event DetectResultReportedEventHandler ResultReported;
        protected void OnDetectResultReported(DetectResultReportedEventArgs e)
        {
            if (ResultReported != null)
            {
                ResultReported(this, e);
            }
        }

        /// <summary>
        /// 当准备任务完成时通知界面执行的操作
        /// </summary>
        public event ReadyTaskCompletedEventHandler ReadyTaskCompleted = null;

        private void OnReadyTaskCompleted(bool frontDetected)
        {
            if (ReadyTaskCompleted != null)
            {
                ReadyTaskCompleted(this, new ReadyTaskCompletedEventArgs(frontDetected));
            }
        }

        /// <summary>
        /// 当准备任务被终止时通知界面执行的操作
        /// </summary>
        public event ReadyTaskAbortedEventHandler TaskAborted = null;

        private void OnTaskAborted(int code, string reason)
        {
            if (TaskAborted != null)
            {
                TaskAborted(this, new ReadyTaskAbortedEventArgs(code, reason));
            }
        }

        public void AddTaskAbortedEvent(ReadyTaskAbortedEventHandler handler)
        {
            if (TaskAborted == null)
            {
                TaskAborted += handler;
            }
        }

        /// <summary>
        /// 照片制证用途
        /// </summary>
        private ApplyTo _apply = ApplyTo.ExitAndEntry;
        public ApplyTo App
        {
            get { return _apply; }
            set { _apply = value; }
        }

        /// <summary>
        /// 取消令牌，用于指示循环任务是否需要继续
        /// </summary>
        private bool _bCancelToken = false;
        public bool CancelToken
        {
            get { return _bCancelToken; }
            set { _bCancelToken = value; }
        }

        /// <summary>
        /// 等待处理事件
        /// </summary>
        private ManualResetEventSlim _mres = new ManualResetEventSlim(false);

        /// <summary>
        /// 用来监视检测各项指标持续的时长
        /// 眼睛：如果连续30秒检测眼睛失败，中止检测和拍照
        /// </summary>
        private Stopwatch _swEyeDetecting = new Stopwatch();

        /// <summary>
        /// 用来监视检测各项指标持续的时长
        /// 正脸：如果正脸连续12秒检测失败，停止检测进入下一步
        /// </summary>
        private Stopwatch _swFrontDetecting = new Stopwatch();

        public Readying(SynchronizationContext uiContext, CapturerBroker capturer)
        {
            _uiContext = uiContext;
            _capturer = capturer;
        }

        #region SynchronizationContext fun
        protected void SendActionToMainThread(SendOrPostCallback d)
        {
            if (_uiContext != null)
            {
                _uiContext.Send(d, null);
            }
        }
        #endregion      
       
        public void InitData()
        {
            // 添加事件监控                     
            _capturer.PhotoCaptured += this.OnPhotoCaptured;        
             _fileName = DateTime.Now.ToString("yyyyMMddHHmmss");
        }

        public void ClearData()
        {
            //移除所有事件监控
            if (_capturer != null)
            {
                _capturer.PhotoCaptured -= this.OnPhotoCaptured;               
            }
            TaskAborted = null;
            ReadyTaskCompleted = null;
            ResultReported = null;
         
        }

        public void OpenProcessSettings()
        {
            _capturer.OpenCameraSettings();
        }

        /// <summary>
        ///  拍照
        /// </summary>
        public void TakePhoto()
        {          
            _capturer.TakePhoto();
        }

        /// <summary>
        /// 在镜头启动后开始工作
        /// </summary>
        public void StartWork()
        {
            Log.AddBeginningBoundary();            
            InitData();
            Task.Factory.StartNew(() => 
            {
                OnWorkItem();
            });
            _mres.Set();
        }

        public void StopWork()
        {
            _bCancelToken = true;
            _mres.Set();
            ClearData();
        }

        /// <summary>
        /// 中断拍照流程
        /// </summary>
        /// <param name="bNormal">拍照业务是否完成</param>
        public void AbortWork()
        {
            _bCancelToken = true;
            _mres.Set();
            ClearData();
            Log.WriteAsync("拍照已中断");
            Log.AddEndingBoundary();           
        }

        private void OnWorkItem()
        {
            Log.WriteAsync("拍照准备工作开始，执行检测...");
            while (!_bCancelToken)
            {
                _mres.Wait();
                if (_bCancelToken)
                {
                    break;
                }
                // 引发拍照事件
                TakePhoto();
                // 等待拍照完成
                _mres.Wait(3000);
                // 获得信号, 准备请求数据
                DetectResultArgs result = null;
                if (!OnRequesting(out result))
                {
                    Thread.Sleep(100);
                    continue;
                }
                HandlingDetectResult(result);
                if (_bCancelToken)
                {
                    break;
                }
            }
            Log.WriteAsync("拍照准备工作结束，停止检测...");
        }

        /// <summary>
        /// 向照片检测服务器请求处理照片，等待返回结果
        /// </summary>
        /// <returns></returns>
        private bool OnRequesting(out DetectResultArgs result)
        {
            _error = "";
            DetectRequestArgs RequestArgs = new DetectRequestArgs();
            RequestArgs.App = _apply;
            RequestArgs.Index = -1;
            RequestArgs.Method = DetectProcessMethods.DetectFront;
            RequestArgs.PhotoName = _fileName;
            string jsonRequestString = JsonConvert.SerializeObject(RequestArgs);
            Log.WriteAsync("1发送请求:" + jsonRequestString);
            PhotoDetectClient client = new PhotoDetectClient("test_pipe", ".");
            string reponseString = client.Request(jsonRequestString);
            //Log.WriteAsync("收到服务器返回信息:" + reponseString);
            if (string.IsNullOrEmpty(reponseString))
            {
                Log.WriteAsync("Server返回结果为空");
                result = new DetectResultArgs();
                result.ErrorMessage = "Server返回结果为空";
                return false;
            }
            try
            {
                result = JsonConvert.DeserializeObject<DetectResultArgs>(reponseString);
                if (!result.Success)
                {
                    Log.WriteAsync("检测执行失败:" + result.ErrorMessage);
                    return false;
                }
                return true;
            }
            catch (Exception ex)
            {
                _error = "解析Server返回数据发生了异常:" + ex.Message;
                Log.WriteAsync(_error);
                Log.WriteException(ex.ToString());
                result = new DetectResultArgs();
                result.ErrorMessage = _error;
                return false;
            }            
        }

        /// <summary>
        /// 处理服务器返回的检测结果;
        /// 检查相关检测项是否合格，由此决定下一步执行的检测方法
        /// </summary>
        private void HandlingDetectResult(DetectResultArgs result)
        {
            RecogOut detectRes = result.Result;
            PassElements elem = detectRes.PassElems;

            if (!elem.FaceEye)
            {
                Log.WriteAsync("眼睛检测失败: " + detectRes.Correction.Tips);
                ReportResultToUI(detectRes);
                if (!_swEyeDetecting.IsRunning)
                {
                    _swEyeDetecting.Restart();
                    return;
                }
                if (_swEyeDetecting.ElapsedMilliseconds > 60000)
                {
                    OnDetectEyeTimeout();
                    return;
                }
                Thread.Sleep(1000);
                return;
            }

            _swEyeDetecting.Reset();
            if (!elem.Front)
            {
                Log.WriteAsync("正脸检测不通过: " + detectRes.Correction.Tips);
                ReportResultToUI(detectRes);
                if (!_swFrontDetecting.IsRunning)
                {
                    _swFrontDetecting.Restart();
                    return;
                }
                if (_swFrontDetecting.ElapsedMilliseconds > 30000)
                {
                    OnReadyTaskCompleted(false);
                    StopWork();
                    return;
                }
                return;
            }
            Log.WriteAsync("正脸识别通过:, 准备完成.");
            OnReadyTaskCompleted(true);
            StopWork();
        }

        /// <summary>
        /// 通常是因为检测不到眼睛
        /// </summary>
        private void OnDetectEyeTimeout()
        {
            OnTaskAborted(0, "眼睛检测失败超时");
            _bCancelToken = true;
            _mres.Set();
            ClearData();
            Log.WriteAsync("拍照中断: 原因是长时间找不到眼睛");
            Log.AddEndingBoundary();    
        }

        /// <summary>
        /// 将检测结果报告给UI线程处理
        /// </summary>
        /// <param name="detectRes"></param>
        private void ReportResultToUI(RecogOut detectRes)
        {          
            TakenPhoto item = null;
            if (detectRes.PassElems.DetectPassed)
            {
                item = new TakenPhoto(-1, detectRes.SourceImagePath, detectRes.DestImagePath);      
            }
            DetectResultReportedEventArgs e = new DetectResultReportedEventArgs(item, detectRes);
            OnDetectResultReported(e);
        }

        private void OnPhotoCaptured(object sender, EventArgs e)
        {
            // 使等待的后台线程获得信号，继续执行后台工作
            _mres.Set();
        }

      
    }
}
